package com.ruoyi.project.dzbqUtil.util;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.dzbqTask.domain.BasDzbq;
import com.ruoyi.project.dzbqTask.domain.DzbqTask;
import com.ruoyi.project.dzbqTask.mapper.BasDzbqMapper;
import com.ruoyi.project.dzbqTask.service.IDzbqTaskService;
import com.ruoyi.project.rf.service.impl.PdaServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.util.List;


/**
 * @ClassName: SocketUtil  电子标签通讯以及 拍灯逻辑处理
 * @Author:
 * @Date: 2023/01/03
 * @Description:
 */

public class SocketUtil {

    private Logger logger = LoggerFactory.getLogger(ExecuteSocket.class);
    private ExecuteSocket socket;
    private Thread tKeep = new Thread(new KeepThread());
    private String host;
    private int port;
    private int connectTime = 0;//socket连接次数
    private IDzbqTaskService dzbqTaskService;
    private BasDzbqMapper basDzbqMapper;


    // 连接以及重新连接
    public void connect(String host, int port) {
        try {
            this.host = host;
            this.port = port;
            tKeep = new Thread(new KeepThread());
            tKeep.start();
            dzbqTaskService = SpringUtils.getBean(IDzbqTaskService.class);
        } catch (Exception e) {
            System.out.println("IP:" + host + ",端口:" + port + ",连接失败.");
        }
    }

    // 发送消息
    public boolean sendMsgSocket(String msg) {
        byte[] bytes = hexStringToByteArray(msg);
        return socket.writeData(bytes);
    }

    private class KeepThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                if (dzbqTaskService == null) {
                    dzbqTaskService = SpringUtils.getBean(IDzbqTaskService.class);
                }
                if (basDzbqMapper == null) {
                    basDzbqMapper = SpringUtils.getBean(BasDzbqMapper.class);
                }
                try {
                    if (socket == null) {
                        socket = new ExecuteSocket(host, port);
                    }

                    //下发亮灯-----------------------------
                    DzbqTask dzbqTaskSend = new DzbqTask();
                    dzbqTaskSend.setStatus("0");
                    dzbqTaskSend.setIp(host);
                    List<DzbqTask> dzbqTaskList = dzbqTaskService.selectDzbqTaskList(dzbqTaskSend);
                    for (DzbqTask task : dzbqTaskList) {
                        try {
                            //亮灯下发   一个灯分左右俩个区域  目前右边下发的是数量  左边是托盘区域号
                            boolean b = sendMsgDzbq(Integer.parseInt(task.getSid()), 0x02, 0x80, Integer.parseInt(task.getFloor()), Integer.parseInt(task.getNum()));
                            logger.info("下发电子标签:ip:" + task.getIp() + ",地址:" + task.getSid() + "数量:" + task.getNum());
                            System.out.println("--------------" + Integer.parseInt(task.getSid()) + "---------------" + b);
                            if (b) {
                                task.setStatus("1");
                                dzbqTaskService.updateDzbqTask(task);
                                logger.info("下发电子标签成功:ip:" + task.getIp() + ",地址:" + task.getSid() + "数量:" + task.getNum());
                            } else {
                                sendMsgDzbq(Integer.parseInt(task.getSid()), 0x02, 0x80, Integer.parseInt(task.getFloor()), Integer.parseInt(task.getNum()));
                            }
                            Thread.sleep(100);
                        } catch (Exception e) {
                            logger.info("下发电子标签失败:" + e.getMessage());
                        }
                    }

                    //拍灯逻辑处理----------------------------------------------------
                    /** 接收电子标签指令 */
                    String content = socket.readData();//读取值
                    if (content.length() > 0) {
                        logger.info("读取电子标签值:" + content);
                    }
                    //将拍灯指令整理成数组
                    String[] split = content.split("5a");
                    for (String s : split) {
                        if (s.length() == 10) {
                            String type = s.substring(4, 6);//指令类型 01是下发成功反馈 12是拍灭绿灯指令
                            if (type.equals("12")) {
                                //12为 绿色拍灯指令
                                int address = new BigInteger(s.substring(2, 4), 16).intValue();
                                int floor = new BigInteger(s.substring(8, 10), 16).intValue();
                                //根据ip地址和层查询 更新拍灯次数
                                BasDzbq basDzb = new BasDzbq();
                                basDzb.setIp(host);
                                basDzb.setColumn(address);
                                List<BasDzbq> basDzbqList = basDzbqMapper.selectBasDzbqList(basDzb);
                                if (basDzbqList.size() > 0) {
                                    Integer pushNum = basDzbqList.get(0).getNum();//拍灯次数
                                    pushNum++;
                                    basDzb.setNum(pushNum);
                                    basDzbqMapper.updateBasDzbq(basDzb);
                                }
                            }
                        }
                    }

                    //读取电子标签拍灯次数
                    BasDzbq basDzb = new BasDzbq();
                    basDzb.setIp(host);
                    List<BasDzbq> basDzbqList = basDzbqMapper.selectBasDzbqList1(basDzb);//查询拍灯次数大于1的 可修改SQL
                    for (BasDzbq basDzbq : basDzbqList) {
                        int i = basDzbq.getColumn();
                        DzbqTask dzbqTask = new DzbqTask();
                        dzbqTask.setIp(host);
                        dzbqTask.setStatus("1");
                        dzbqTask.setSid(String.valueOf(i));
                        PdaServiceImpl pdaService = SpringUtils.getBean(PdaServiceImpl.class);
                        List<DzbqTask> dzbqTasks = dzbqTaskService.selectDzbqTaskList(dzbqTask);
                        if (dzbqTasks.size() > 0) {
                            //灭灯
                            boolean b = sendDzbqOff(i);
                            if (!b) {
                                sendDzbqOff(i);
                            }
                            logger.info("下发电子标签灭灯:ip:" + host + ",地址:" + i);
                            //每次拍灯计算当前指令是否还有可下发数量，若有则更新完成数量,状态改为2已拍灯
                            //查询该订单下所有的灯都已下发，再下发下一轮的亮灯任务
                            for (DzbqTask task : dzbqTasks) {
                                //TODO 排灯触发的逻辑处理
                                AjaxResult ajaxResult  = pdaService.outSure(task.getTrayCode(),task.getTrayCode(), "");
                                if (ajaxResult.get("code").equals("0")) {
                                    //删除该指令
                                    int row = dzbqTaskService.deleteDzbqTaskById(task.getId());
                                    if (row == 0) {
                                        break;
                                    }
                                }
                            }
                        } else {
                            sendDzbqOff(i);
                            logger.info("下发电子标签二次灭灯:ip:" + host + ",地址:" + i);
                        }
                    }
                    //将电子标签拍灯次数清0
                    if (basDzbqList.size() > 0){
                        basDzbqMapper.updateBasDzbq0(basDzb);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        connectTime++;
                        if (connectTime > 300) {
                            socket.close();
                            socket = null;
                            connectTime = 0;
                        }

                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public static String byteArrayToHexString(byte b[], int len) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < len; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

    /**
     * 16进制转字符串
     *
     * @param b
     * @param len
     * @return
     */
    public static String byteArrayToString(byte b[], int len) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 5; i++) {
            char c = (char) b[i];
            sb.append(c);
        }
        return sb.toString();
    }

    public static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

    public static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * 16进制表示的字符串转换为字节数组
     *
     * @param hexString 16进制表示的字符串
     * @return byte[] 字节数组
     */
    public static byte[] hexStringToByteArray(String hexString) {
        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个字节
            bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
                    .digit(hexString.charAt(i + 1), 16));
        }
        return bytes;
    }

    /**
     * 灭灯
     *
     * @param address
     */
    public boolean sendDzbqOff(int address) {
        int x7 = (address + 0x10 + 0x00 + 0x03 + 0xe8 + 0x03 + 0xe8) % 256;//累加 校验
        return sendMsgSocket("FA " + String.format("%02x", address) + " 10 00 03 e8 03 e8 " + String.format("%02x", x7) + " AF");
    }

    /**
     * @param sid   地址
     * @param x1    亮灯指令
     * @param x2    灯带控制 闪烁频率
     * @param leftText 绿色数值(左)
     * @param num   红色数值(右)
     */
    public boolean sendMsgDzbq(int sid, int x1, int x2, int leftText, int num) {
        String green = String.format("%04x", leftText);
        String red = String.format("%04x", num);
        String greenFirst2 = green.substring(0, 2);
        String greenLast2 = green.substring(2);
        String redFirst2 = red.substring(0, 2);
        String redLast2 = red.substring(2);
        int x3 = Integer.parseInt(greenFirst2, 16);//绿色数值
        int x4 = Integer.parseInt(greenLast2, 16);//绿色数值
        int x5 = Integer.parseInt(redFirst2, 16);//红色数值
        int x6 = Integer.parseInt(redLast2, 16);//红色数值
        int x7 = (sid + x1 + x2 + x3 + x4 + x5 + x6) % 256;//累加 校验
        String value = "FA" + String.format("%02x", sid) + String.format("%02x", x1) + String.format("%02x", x2) + greenFirst2 +
                greenLast2 + redFirst2 + redLast2 + String.format("%02x", x7) + "AF";
        System.out.println(value);
        return sendMsgSocket(value);
    }
}
